home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 4 / BBS in a Box - Macintosh - Volume IV (January 1992) (BBS in a Box).iso / Files / Prog / N-P / PixelViewCode < prev    next >
Encoding:
Text File  |  1988-07-21  |  33.6 KB  |  1,073 lines  |  [TEXT/MACA]

  1. PROGRAM Viewer;
  2.  
  3. {--------------------- A Viewer for PixelPaint 1.0 ---------------------}
  4. {--------------------- Written by Keith McGreggor  ---------------------}
  5. {--------------------- (c) 1987 by Pixel Resources, Inc.  --------------}
  6. {--------------------- Commercial Rights Reserved  ---------------------}
  7. {--------------------- --------------------------  ---------------------}
  8. {------ It is my intention that this evolve into a general graphic -----}
  9. {------ file conversion utility.  You may modify this code in any  -----}
  10. {------ way you want, as long as you then upload the application   -----}
  11. {------ and source code for other authors to contribute to and to  -----}
  12. {------ learn from.  In this way, we can each explore other file   -----}
  13. {------ formats, and (eventually) come up with a single color file -----}
  14. {------ specification.                                             -----}
  15. {------                                  --- Keith McGreggor       -----}
  16. {-----------------------------------------------------------------------}
  17.  
  18.     USES
  19.         Memtypes,Quickdraw,Osintf,Toolintf,Packintf;
  20.  
  21.     PROCEDURE _DataInit; EXTERNAL;
  22.  
  23. {------------------------------------------------------------------------------}
  24.  
  25.     TYPE
  26.         ColorMapType = ARRAY[ 0..255 ] OF ColorSpec;
  27.         TextureMapType = ARRAY [ 0..143 ] OF Pattern; 
  28.         ViewRecord = RECORD
  29.                 ViewOpen : Boolean;                    { is the Window open }
  30.                 FullView : Boolean;                    { is the whold document visible }
  31.                 WindowType : Integer;                { 5-Scollable 6-NoGrow 7-NoTitleNoGrow }
  32.                 WindowPortRect : Rect;                { PortRect of Window }
  33.                 ReadOnlyWindow : Boolean;            { true if window is on low-res screen }
  34.                 DocScreenRect : Rect;                { Window Area containing the Document }
  35.                 DeskZoomRect : Rect;                { StdState in window's ZoomRect }
  36.                 DeskUserRect : Rect;                { UserState in window's ZoomRect }
  37.                 AnchorRect : Rect;                    { area of Document showing }
  38.                 ZoomMode : Integer;                    { what level of fatbits }
  39.                 Zoomanchor : Point;                    { future use }
  40.                 Splitlocation : Integer;            { future use }
  41.                 RulerOrigin : Point;                { origin of rulers }
  42.                 RulerUnits : Integer;                { pixels, inches, metric, picas }
  43.                 RulersOpen : Boolean;                { are rulers showing }
  44.                 HeightScrollBar : ControlHandle;    { handle to Horz Scroll Bars }
  45.                 WidthScrollBar : ControlHandle;        { handle to Vert Scroll Bars }
  46.                 ViewPtr : WindowPtr;                { WindowPtr }
  47.                 LinkUp : Integer;                    { future use }
  48.                 fatrect : Rect;                        { window coords of fatbits rect }
  49.                 reserved : ARRAY [1..2] OF LongInt;    { future use}
  50.             END;
  51.         FileHeaderPtr = ^FileHeader;
  52.         FileHeader = RECORD
  53.                 Version : LongInt;                    { file version type (should be MAXINT) }
  54.                 PatArray : ARRAY[1..36] OF Pattern;    { future use }
  55.                 CanvasSize : Integer;                { 1-576x720 2-512x512 3-1024x1024 4-1024x768}
  56.                 CanvasDepth : Integer;                { bits per pixel }
  57.                 WindType : Integer;                    { Default window type }
  58.                 ViewsUsed : Integer;                { Currently set to 1 }
  59.                 ViewArray : ARRAY[1..8] OF ViewRecord;
  60.                 OVOpen : Boolean;                    { Is Overview Open }
  61.                 CurrentOV : Integer;                { index of current OV windowsel }
  62.                 OVPoint : Point;                    { topleft pt of Overview Window }
  63.                 RulerUnit : Integer;                { Default Ruler Unit }
  64.                 OtherFont : Integer;                { font size of Other font }
  65.                 GridSize : Integer;                    { grid size }
  66.                 FXButton : Boolean;                    { true if set for all tools }
  67.                 IconMargin : Boolean;                { true if leave room for icons }
  68.                 MseCrawl : Boolean;                    { true if not mouse crawl }
  69.                 FatbitScroll : Boolean;                { true if fatbit autoscroll }
  70.                 cornerstretch : Boolean;            { true if stretch from corners }
  71.                 RemapColors : Boolean;                { true if color remapping is on }
  72.                 patternopt : Integer;                 { opcode number for Option Key effects }
  73.                 noOfHues : Integer;                    { number of absolute hues in the palette }
  74.                 spraycansize : Integer;              { for later use }
  75.             END;
  76.  
  77.     VAR
  78.         applemenu, filemenu, editmenu    : MenuHandle;
  79.         watch                            : CursHandle;
  80.         viewwindowrecord                : WindowRecord;
  81.         viewwindow                        : WindowPtr;
  82.         viewevent                        : EventRecord;
  83.         userwantstoquit                    : Boolean;
  84.         horizontalscroll,verticalscroll : ControlHandle;
  85.         draggingarea                    : Rect;
  86.         documentwidth,documentheight    : Integer;
  87.         bufferport                        : CGrafPtr;
  88.         bufferpix                        : PixMapHandle;
  89.         docport                            : CGrafPtr;
  90.         docpix                            : PixMapHandle;
  91.         docsize                            : Integer;
  92.         anchorpt,docpt                    : Point;
  93.         mycolormap                        : ColorMapType;
  94.  
  95. {------------------------------------------------------------------------------}
  96. {$S COLORSTUFF}        
  97. {-----------------------------------------------------------------------------------------}
  98.  
  99.     FUNCTION CreatePixMap( VAR mypixmap : PixMapHandle; width, height, depth : Integer ) : Boolean;
  100.     VAR
  101.         thegdevice : GDHandle;
  102.         myptr : Ptr;
  103.         bitsperrow,bytesperrow,bytesneeded : LongInt;
  104.     BEGIN
  105.         thegdevice := GetGDevice;
  106.         CreatePixMap := false;
  107.         mypixmap := NewPixMap; 
  108.         bitsperrow := LongInt( depth * width );    
  109.         bytesperrow := bitsperrow div 8;
  110.         IF (odd(bytesperrow)) THEN bytesperrow := bytesperrow + 1;
  111.         bytesneeded := bytesperrow * height;
  112.         myptr := nil;
  113.         myptr := Ptr( NewPtr( bytesneeded ) );
  114.         IF (myptr <> NIL) THEN BEGIN
  115.             mypixmap^^.baseaddr := myptr;
  116.             mypixmap^^.rowbytes := Integer(bytesperrow + 32768);  
  117.             SetRect(mypixmap^^.bounds,0,0,width,height);
  118.             mypixmap^^.pmtable := thegdevice^^.gdpmap^^.pmtable;  
  119.             mypixmap^^.pixelsize := depth;
  120.             mypixmap^^.cmpsize := depth; 
  121.             CreatePixMap := true;
  122.             END
  123.         ELSE CreatePixMap := false;
  124.     END;
  125.  
  126. {------------------------------------------------------------------------------}
  127.  
  128.     FUNCTION BuildNewPort( VAR myport : CGrafPtr; VAR mypixmap : PixMapHandle;
  129.                         width, height, depth : Integer ) : Boolean;
  130.     VAR
  131.         result : Boolean;
  132.         savedport : GrafPtr;
  133.     BEGIN
  134.         GetPort(savedport);
  135.         myport := NIL;
  136.         myport := CGrafPtr( NewPtr( sizeof(CGrafPort) ) ); 
  137.         result := CreatePixMap( mypixmap, width, height, depth );
  138.         IF ((myport <> NIL) AND result) THEN BEGIN
  139.             OpenCPort(myport);
  140.             SetPort(grafptr(myport));
  141.             myport^.portpixmap := mypixmap;
  142.             PortSize(mypixmap^^.bounds.right,mypixmap^^.bounds.bottom);
  143.             ClipRect(mypixmap^^.bounds);
  144.             myport^.visrgn := myport^.cliprgn;
  145.             EraseRect(myport^.portrect);
  146.             BuildNewPort := true;
  147.             END
  148.         ELSE BuildNewPort := False;
  149.         SetPort(savedport);
  150.     END;
  151.     
  152. {-----------------------------------------------------------------------------------------}
  153.  
  154.     PROCEDURE PixelSetEntries(start, count: INTEGER; aptr: ptr); INLINE $AA3F;
  155.     
  156. {-----------------------------------------------------------------------------------------}
  157.  
  158.     PROCEDURE SetColorMap(mymap : ColorMapType);
  159.     VAR
  160.         i : integer;
  161.         wmp : grafptr;
  162.         oldport : grafptr;
  163.     BEGIN
  164.         IF GetMainDevice^^.gdPMap^^.pmtable^^.ctsize <> 255 THEN Exit(SetColorMap);
  165.         mymap[0].rgb.red := $FFFF;
  166.         mymap[0].rgb.blue := $FFFF;
  167.         mymap[0].rgb.green := $FFFF;
  168.         mymap[255].rgb.red := $0000;
  169.         mymap[255].rgb.blue := $0000;
  170.         mymap[255].rgb.green := $0000;
  171.         FOR i := 1 TO 254 DO
  172.             IF (mymap[i].rgb.red = $FFFF) AND (mymap[i].rgb.blue = $FFFF) 
  173.                 AND (mymap[i].rgb.green = $FFFF) THEN BEGIN
  174.                         mymap[i].rgb.red := $FFFE;
  175.                         mymap[i].rgb.blue := $FFFE;
  176.                         mymap[i].rgb.green := $FFFE;
  177.                 END
  178.             ELSE IF (mymap[i].rgb.red = $0000) AND (mymap[i].rgb.blue = $0000) 
  179.                 AND (mymap[i].rgb.green = $0000) THEN BEGIN
  180.                         mymap[i].rgb.red := $0001;
  181.                         mymap[i].rgb.blue := $0001;
  182.                         mymap[i].rgb.green := $0001;
  183.                 END;
  184.         SetGDevice(GetMainDevice);
  185.         FOR i := 0 TO 255 DO BEGIN ProtectEntry(i,false); ReserveEntry(i,false); END;
  186.         PixelSetEntries(0,255,@mymap);
  187.         FOR i := 0 TO 255 DO ProtectEntry(i,true); 
  188.         GetPort(oldport);
  189.         IF oldport = viewwindow THEN BEGIN
  190.             GetWMgrPort(wmp);
  191.             IF wmp <> nil THEN PaintOne(nil, wmp^.cliprgn);
  192.             SetPort(viewwindow);
  193.             END;
  194.     END;
  195.  
  196. {-----------------------------------------------------------------------------------------}
  197.  
  198.     PROCEDURE SetForegroundColor( cv : Integer );
  199.     VAR
  200.         aport : grafptr;
  201.     BEGIN
  202.         getport(aport);
  203.         if (bitand(cgrafptr(aport)^.portversion,$C000) <> $C000) then  EXIT(SetForegroundColor);
  204.         rgbforecolor(MyColorMap[cv].rgb);
  205.         IF GetMainDevice^^.gdPMap^^.Pixeltype = 1 THEN EXIT(SetForegroundColor);
  206.         cgrafptr(aport)^.fgcolor := longint(cv);
  207.     END;
  208.     
  209. {-----------------------------------------------------------------------------------------}
  210.  
  211.     PROCEDURE SetBackgroundColor( cv : Integer );
  212.     VAR
  213.         aport : grafptr;
  214.     BEGIN
  215.         getport(aport);
  216.         if (bitand(cgrafptr(aport)^.portversion,$C000) <> $C000) then  EXIT(SetBackgroundColor);
  217.         rgbbackcolor(MyColorMap[cv].rgb);
  218.         IF GetMainDevice^^.gdPMap^^.Pixeltype = 1 THEN EXIT(SetBackgroundColor);
  219.         cgrafptr(aport)^.bkcolor := longint(cv);
  220.     END;
  221.     
  222. {------------------------------------------------------------------------------}
  223.  
  224.     PROCEDURE AppleStandardClut;
  225.     VAR
  226.         asc : CTabHandle;
  227.         i : Integer;
  228.     BEGIN
  229.         IF GetMainDevice^^.gdPMap^^.Pixeltype = 1 THEN Exit(AppleStandardClut);
  230.         asc := nil;
  231.         asc := GetCTable(0);
  232.         IF (asc = nil) THEN Exit(AppleStandardClut);
  233.         for i := 0 to 255 do MyColorMap[i] := asc^^.ctTable[i];
  234.         DisposCTable(asc);
  235.         SetColorMap(MyColorMap);
  236.     END;
  237.     
  238. {------------------------------------------------------------------------------}
  239. {$ IMAGE }
  240. {------------------------------------------------------------------------------}
  241.  
  242.     PROCEDURE ReconstructImage;
  243.     VAR    
  244.         onscreenrect,offscreenrect : Rect;
  245.         viewwidth,viewheight,blastwidth,blastheight : Integer;
  246.         temprect : Rect;
  247.     BEGIN
  248.         SetPort(viewwindow);
  249.         viewwidth := viewwindow^.portrect.right - viewwindow^.portrect.left - 16;
  250.         viewheight := viewwindow^.portrect.bottom - viewwindow^.portrect.top - 16;
  251.         blastwidth := viewwidth;
  252.         blastheight := viewheight;
  253.         IF (viewwidth > documentwidth) then blastwidth := documentwidth;
  254.         IF (viewheight > documentheight) THEN blastheight := documentheight;
  255.         SetRect(onscreenrect,0,0,blastwidth,blastheight);
  256.         SetRect(offscreenrect,0,0,blastwidth,blastheight);
  257.         OffsetRect(offscreenrect,GetCtlValue(horizontalscroll),GetCtlValue(verticalscroll));
  258.         SetColorMap(MyColorMap);
  259.         Pennormal;
  260.         SetForegroundColor(255);
  261.         SetBackgroundColor(0);
  262.         CopyBits( GrafPtr(docport)^.portBits, GrafPtr(viewwindow)^.portBits,
  263.                     offscreenrect,onscreenrect,srccopy,nil);
  264.         SetRect(temprect,0,blastheight,viewwidth,viewheight);
  265.         PenNormal;
  266.         PenPat(gray);
  267.         PaintRect(temprect);
  268.         SetRect(temprect,blastwidth,0,viewwidth,viewheight);
  269.         PaintRect(temprect);
  270.         PenNormal;
  271.     END;
  272.     
  273. {------------------------------------------------------------------------------}
  274. {$S UTILITIES}        
  275. {------------------------------------------------------------------------------}
  276.  
  277.     PROCEDURE ViewerError( errormessage : Str255 );
  278.     VAR
  279.         itemhit      : Integer;
  280.     BEGIN
  281.         ParamText(errormessage,'','','');
  282.         sysbeep(1);
  283.         itemhit := NoteAlert(4000,nil);
  284.     END;
  285.  
  286. {------------------------------------------------------------------------------}
  287.  
  288.     PROCEDURE ResumeProc;
  289.     BEGIN
  290.         AppleStandardClut;            
  291.         ExitToShell;
  292.     END;
  293.  
  294.  
  295. {------------------------------------------------------------------------------}
  296.  
  297.     FUNCTION ColorQDExists : Boolean;
  298.     TYPE
  299.         WordPtr = ^Integer;
  300.     BEGIN
  301.         ColorQDExists := BAND(WordPtr($28E)^,$C000) = 0;
  302.     END;
  303.  
  304. {------------------------------------------------------------------------------}
  305.  
  306.     FUNCTION DeviceHasEnoughColor : Boolean;
  307.     BEGIN
  308.         DeviceHasEnoughColor := GetMainDevice^^.gdPMap^^.pmtable^^.ctsize = 255;
  309.     END;
  310.  
  311. {------------------------------------------------------------------------------}
  312.  
  313.     FUNCTION RunningUnderMultiFinder : Boolean;
  314.     CONST
  315.         WNETrapNum = $60;
  316.         UnImplTrapNum = $9F;
  317.     BEGIN
  318.         RunningUnderMultiFinder := GetTrapAddress(WNETrapNum) <> GetTrapAddress(UnImplTrapNum);
  319.     END;
  320.  
  321. {------------------------------------------------------------------------------}
  322.  
  323.     FUNCTION HorizontalFit ( somewindow : WindowPtr ) : Rect;
  324.     VAR
  325.         width,top : Integer;
  326.         temprect  : Rect;
  327.     BEGIN
  328.         width := somewindow^.portrect.right - somewindow^.portrect.left - 15;
  329.         top := somewindow^.portrect.bottom - somewindow^.portrect.top - 15;
  330.         SetRect(temprect,-1,top,width+1,top+16);
  331.         HorizontalFit := temprect;
  332.     END;
  333.  
  334. {------------------------------------------------------------------------------}
  335.  
  336.     FUNCTION VerticalFit ( somewindow : WindowPtr ) : Rect;
  337.     VAR
  338.         height,left : Integer;
  339.         temprect  : Rect;
  340.     BEGIN
  341.         height := somewindow^.portrect.bottom - somewindow^.portrect.top - 15;
  342.         left := somewindow^.portrect.right - somewindow^.portrect.left - 15;
  343.         SetRect(temprect,left,-1,left+16,height+1);
  344.         VerticalFit := temprect;
  345.     END;
  346.  
  347. {------------------------------------------------------------------------------}
  348.  
  349.     PROCEDURE AdjustScrollLimits;
  350.     VAR
  351.         horizontallimit,verticallimit : Integer;
  352.     BEGIN
  353.         horizontallimit := documentwidth - viewwindow^.portrect.right 
  354.                             + viewwindow^.portrect.left + 16;
  355.         verticallimit := documentheight - viewwindow^.portrect.bottom 
  356.                             + viewwindow^.portrect.top + 16;
  357.         IF horizontallimit < 0 THEN horizontallimit := 0;
  358.         IF verticallimit < 0 THEN verticallimit := 0;
  359.         SetCtlMax(horizontalscroll,horizontallimit);
  360.         SetCtlMax(verticalscroll,verticallimit);
  361.         ReconstructImage;
  362.     END;
  363.  
  364. {------------------------------------------------------------------------------}
  365. {$ INITIALIZE }
  366. {------------------------------------------------------------------------------}
  367.  
  368.     PROCEDURE SetupTheMac;
  369.     BEGIN
  370.         UnloadSeg(@_DataInit);
  371.         InitGraf(@thePort);
  372.         MoreMasters;                
  373.         MoreMasters;                
  374.         MoreMasters;                
  375.         MoreMasters;                
  376.         MoreMasters;                
  377.         MoreMasters;                
  378.         MoreMasters;                
  379.         MoreMasters;                
  380.         InitFonts;
  381.         FlushEvents(everyEvent,0);
  382.         InitWindows;
  383.         InitMenus;
  384.         TEInit;
  385.         InitDialogs(@ResumeProc);
  386.         MaxApplZone;
  387.         InitCursor;
  388.         
  389.         watch := GetCursor(WatchCursor);
  390.         SetCursor(watch^^);
  391.         SetRect(draggingarea,4,24,screenBits.bounds.right-4,screenBits.bounds.bottom-4);
  392.         
  393.         IF NOT ColorQDExists THEN BEGIN
  394.             ViewerError('You need a Mac II to run this program.');
  395.             ExitToShell;
  396.             END;
  397.         
  398.         IF NOT DeviceHasEnoughColor THEN BEGIN
  399.             ViewerError('You need to have 256 colors available to run this program.');
  400.             ExitToShell;
  401.             END;
  402.  
  403.     END;
  404.     
  405. {------------------------------------------------------------------------------}
  406.  
  407.     PROCEDURE SetupTheWindow;
  408.     VAR
  409.         temprect : Rect;
  410.     BEGIN
  411.         SetRect(temprect,50,50,500,400);
  412.         viewwindow := NewCWindow(@viewwindowrecord,temprect,'Untitled',
  413.                                 false,8,pointer(-1),true,0);
  414.         horizontalscroll := NewControl(viewwindow,HorizontalFit(viewwindow),
  415.                                 'Horizontal',true,0,0,1,16,0);
  416.         verticalscroll := NewControl(viewwindow,VerticalFit(viewwindow),
  417.                                 'Vertical',true,0,0,1,16,0);
  418.         DrawGrowIcon(viewwindow);
  419.     END;
  420.     
  421. {------------------------------------------------------------------------------}
  422.  
  423.     PROCEDURE SetupTheMenus;
  424.     BEGIN
  425.         applemenu := NewMenu(1,'');
  426.         filemenu  := NewMenu(2,'File');
  427.         editmenu  := NewMenu(3,'Edit');
  428.         AppendMenu(applemenu,'About PixelPaintâ„¢ Viewer...;(-');
  429.         AppendMenu(filemenu,'View FullSize Doc.../O;View HalfSize Doc.../H;(Close/W;(-;Quit/Q');
  430.         AppendMenu(editmenu,'Undo/Z;(-;Cut/X;Copy/C;Paste/V;Clear/B');
  431.         AddResMenu(applemenu,'DRVR');
  432.         InsertMenu(applemenu,0);
  433.         InsertMenu(filemenu,0);
  434.         InsertMenu(editmenu,0);
  435.         DisableItem(editmenu,0);
  436.         DrawMenuBar;
  437.     END;
  438.  
  439. {------------------------------------------------------------------------------}
  440.  
  441.     PROCEDURE FindTheMaxDocumentSize;
  442.     VAR
  443.         enoughroom    : Ptr;
  444.     BEGIN
  445.         enoughroom := nil;
  446.         enoughroom := NewPtr(1300000);
  447.         IF (enoughroom <> nil) THEN BEGIN
  448.             DisposPtr(enoughroom);
  449.             documentwidth := 1024;
  450.             documentheight := 1024;
  451.             END
  452.         ELSE BEGIN
  453.             enoughroom := NewPtr(560000);
  454.             IF (enoughroom <> nil) THEN BEGIN
  455.                 DisposPtr(enoughroom);
  456.                 documentwidth := 576;
  457.                 documentheight := 720;
  458.                 END
  459.             ELSE BEGIN
  460.                 enoughroom := NewPtr(360000);
  461.                 IF (enoughroom <> nil) THEN BEGIN
  462.                     DisposPtr(enoughroom);
  463.                     documentwidth := 512;
  464.                     documentheight := 512;
  465.                     END
  466.                 ELSE BEGIN
  467.                     ViewerError('You don''t seem to have enough room to run this program.');
  468.                     ExitToShell;
  469.                     END;
  470.                 END;
  471.             END;
  472.     END;
  473.  
  474.  
  475. {------------------------------------------------------------------------------}
  476.  
  477.     PROCEDURE SetupTheDocument;
  478.     VAR
  479.         someport : GrafPtr;
  480.     BEGIN
  481.         FindTheMaxDocumentSize;
  482.         IF NOT BuildNewPort(bufferport,bufferpix,1024,64,8) THEN BEGIN
  483.             ViewerError('You don''t seem to have enough room to run this program.');
  484.             ExitToShell;
  485.             END;
  486.         IF NOT BuildNewPort(docport,docpix, documentwidth, documentheight, 8) THEN BEGIN
  487.             ViewerError('You don''t seem to have enough room to run this program.');
  488.             ExitToShell;
  489.             END;
  490.         GetPort(someport);
  491.         SetPort(GrafPtr(bufferport));
  492.         AppleStandardClut;
  493.         SetPort(GrafPtr(docport));
  494.         PortSize(documentwidth,documentheight);
  495.         AppleStandardClut;
  496.         SetPort(someport);
  497.         SetPt(docpt,0,0);
  498.         SetPt(anchorpt,0,0);
  499.         setport(viewwindow);
  500.         AppleStandardClut;
  501.     END;
  502.     
  503. {------------------------------------------------------------------------------}
  504.  
  505.     PROCEDURE InitThings;
  506.     BEGIN
  507.         SetupTheMac;
  508.         SetupTheWindow;
  509.         SetupTheMenus;
  510.         SetupTheDocument;
  511.         InitCursor;
  512.     END;
  513.     
  514. {------------------------------------------------------------------------------}
  515. {$ FILE }
  516. {------------------------------------------------------------------------------}
  517.  
  518.     FUNCTION FileError( errorcode : Integer ) : Boolean;
  519.     VAR
  520.         fileerrormessage : Str255;
  521.     BEGIN
  522.         FileError := false;
  523.         IF errorcode <> 0 THEN BEGIN
  524.             NumToString(errorcode,fileerrormessage);
  525.             fileerrormessage := Concat('File Error #',fileerrormessage,'... Cannot continue. ');
  526.             ViewerError( fileerrormessage );
  527.             FileError := true;
  528.             END;
  529.     END;
  530.     
  531. {------------------------------------------------------------------------------}
  532.  
  533.     FUNCTION OpeningConversation( whattype : OSType; VAR reply : SFReply ) : Boolean;
  534.     VAR
  535.         typeslist : SFTypeList;
  536.         somept : Point;
  537.     BEGIN
  538.         typeslist[0] := whattype;
  539.         SetPt(somept,80,80);
  540.         SFGetFile(somept,'Open...',nil,1,typeslist,nil,reply);
  541.         OpeningConversation := reply.good;
  542.     END;
  543.     
  544. {------------------------------------------------------------------------------}
  545.  
  546.     FUNCTION SavingConversation( whattype : OSType; VAR reply : SFReply ) : Boolean;
  547.     VAR
  548.         typeslist : SFTypeList;
  549.         somept : Point;
  550.         name : Str255;
  551.     BEGIN
  552.         typeslist[0] := whattype;
  553.         SetPt(somept,80,80);
  554.         GetWTitle(viewwindow,name);
  555.         SFPutFile(somept,'Save as...',name,nil,reply);
  556.         SavingConversation := reply.good;
  557.     END;
  558.     
  559. {------------------------------------------------------------------------------}
  560.  
  561.     FUNCTION ReadPixelPaintHeader( thefilenumber : Integer ) : Boolean;
  562.     LABEL    
  563.         1;
  564.     VAR
  565.         texturebuffer,headerbuffer : Ptr;
  566.         colorspace,headerspace,texturespace : LongInt;
  567.         savedport : GrafPtr;
  568.     BEGIN
  569.         ReadPixelPaintHeader := false;
  570.         headerbuffer := nil;
  571.         texturebuffer := nil;
  572.         headerspace := sizeof(FileHeader);
  573.         colorspace := sizeof(ColorMapType);
  574.         texturespace := sizeof(TextureMapType);
  575.         purgemem(500000);
  576.         headerbuffer := NewPtr(headerspace);
  577.         texturebuffer := NewPtr(texturespace);
  578.         IF (headerbuffer = nil) OR (texturebuffer = nil) THEN BEGIN
  579.             ViewerError('Cannot allocate enough buffer space.');
  580.             GOTO 1;
  581.             END;
  582.         IF FileError(SetFPos(thefilenumber,fsFromStart,0)) THEN GOTO 1;
  583.         IF FileError(FSRead(thefilenumber,headerspace,headerbuffer)) THEN GOTO 1;
  584.         IF FileHeaderPtr(headerbuffer)^.Version <> MaxInt THEN BEGIN
  585.             ViewerError('This document cannot be read by this program.');
  586.             GOTO 1;
  587.             END;
  588.         docsize := FileHeaderPtr(headerbuffer)^.CanvasSize;
  589.         IF FileError(FSRead(thefilenumber,colorspace,@MyColorMap)) THEN GOTO 1;
  590.         GetPort(savedport);
  591.         SetPort(GrafPtr(bufferport));
  592.         SetColorMap(MyColorMap);
  593.         SetPort(GrafPtr(docport));
  594.         SetColorMap(MyColorMap);
  595.         SetPort(savedport);
  596.         IF FileError(FSRead(thefilenumber,texturespace,texturebuffer)) THEN GOTO 1;
  597.         ReadPixelPaintHeader := true;
  598.     1:
  599.         IF (headerbuffer <> nil) THEN DisposPtr(Ptr(headerbuffer));
  600.         IF (texturebuffer <> nil) THEN DisposPtr(texturebuffer);
  601.     END;
  602.     
  603. {------------------------------------------------------------------------------}
  604.  
  605.     FUNCTION GenericLoader(thefilenumber : Integer;
  606.                             thescreenrect : Rect; 
  607.                             bottomofpict : Integer; 
  608.                             rightofpict : Integer; 
  609.                             scaleamt : Integer) : Boolean;
  610.     LABEL
  611.         1;
  612.     TYPE
  613.         ByteBuffer = ARRAY[1..65] OF Char;
  614.     VAR
  615.         permdstptr, dstptr, srcptr : ptr;
  616.         bufferrect, dstrect, trect :Rect;
  617.         maxscanlines : integer;
  618.         numbercompressed, count : longint;
  619.         errCode, scanline, i : Integer;
  620.         srcBuffer : ByteBuffer;
  621.         aport : grafptr;
  622.         
  623.         FUNCTION OkayToBlast(x : Integer) : Boolean;
  624.         BEGIN
  625.             IF scaleamt = 1 THEN OkayToBlast := true
  626.             ELSE IF (x mod scaleamt) = 0 THEN OkayToBlast := true
  627.             ELSE OkayToBlast := false;
  628.         END;
  629.         
  630.     BEGIN
  631.         GetPort(aport);
  632.         GenericLoader := false;
  633.         permdstPtr := Ptr(bufferpix^^.baseaddr);
  634.         SetRect(bufferrect, 0, 0, rightofpict, scaleamt);
  635.         trect := thescreenrect;
  636.         trect.bottom := trect.top + 1;
  637.         PenNormal;
  638.         SetForegroundColor(255);
  639.         SetBackgroundColor(0);
  640.         dstptr := permdstPtr;
  641.         FOR scanLine := 1 TO bottomofpict DO BEGIN
  642.             FOR i := 1 TO 16 DO BEGIN
  643.                 count := 4;
  644.                 IF FileError(FSRead(thefilenumber,count,@numbercompressed)) THEN GOTO 1;
  645.                 IF FileError(FSRead(thefilenumber,numbercompressed,@srcbuffer)) THEN GOTO 1;
  646.                 srcptr := @srcbuffer;
  647.                 UnPackBits(srcptr,dstptr,64);
  648.                 END;
  649.             IF OkayToBlast(scanline) THEN BEGIN
  650.                 dstrect := trect;
  651.                 offsetrect(dstrect, 0, (scanline div scaleamt) - 1);
  652.                 CopyBits(grafptr(bufferport)^.portBits,aport^.portBits,
  653.                          bufferrect,dstrect,srccopy,nil);
  654.                 dstptr := permdstPtr;
  655.                 END;
  656.             end;
  657.         GenericLoader := true;
  658.     1:
  659.     END;
  660.     
  661. {------------------------------------------------------------------------------}
  662.  
  663.     FUNCTION ReadPixelPaintDoc( thefilenumber : Integer; Scaling : Integer ) : Boolean;
  664.     VAR
  665.         x,y : Integer;
  666.         myrect : Rect;
  667.     BEGIN
  668.         CASE docsize OF
  669.             1: BEGIN x := 576; y := 720; END;
  670.             2: BEGIN x := 512; y := 512; END;
  671.             3: BEGIN x := 1024; y := 1024; END;
  672.             4: BEGIN x := 1024; y := 768; END;
  673.             END;
  674.         SetRect(myrect,0,0,(x div scaling),y);
  675.         SetPort(GrafPtr(docport));
  676.         SetForegroundColor(255);
  677.         SetBackgroundColor(0);
  678.         PenNormal;
  679.         PenPat(ltgray);
  680.         PaintRect(docport^.portrect);
  681.         PenNormal;
  682.         ReadPixelPaintDoc := GenericLoader(thefilenumber,myrect,y,x,Scaling);
  683.     END;
  684.     
  685. {------------------------------------------------------------------------------}
  686.  
  687.     PROCEDURE DoOpenPixelPaint( scaling : Integer );
  688.     VAR
  689.         answer : SFReply;
  690.         headerisokay,docisokay : Boolean;
  691.         thefilenumber : Integer;
  692.         oldvolref : Integer;
  693.     BEGIN
  694.         headerisokay := false;
  695.         docisokay := false;
  696.         IF NOT OpeningConversation('PX01',answer) THEN Exit(DoOpenPixelPaint);
  697.         SetCursor(watch^^);
  698.         IF FileError( GetVol(nil,oldvolref) ) THEN Exit(DoOpenPixelPaint);
  699.         IF FileError( SetVol(nil,answer.vrefnum) ) THEN Exit(DoOpenPixelPaint);
  700.         IF FileError( FSOpen(answer.fname,answer.vrefnum,thefilenumber) ) THEN Exit(DoOpenPixelPaint);
  701.         headerisokay := ReadPixelPaintHeader(thefilenumber);
  702.         IF headerisokay THEN
  703.             docisokay := ReadPixelPaintDoc(thefilenumber,scaling);
  704.         IF FileError( FSClose(thefilenumber) ) THEN Exit(DoOpenPixelPaint);
  705.         IF FileError( SetVol(nil,oldvolref) ) THEN Exit(DoOpenPixelPaint);
  706.         IF (NOT headerisokay) OR (NOT docisokay) THEN Exit(DoOpenPixelPaint);
  707.         ShowWindow(viewwindow);
  708.         SelectWindow(viewwindow);
  709.         DisableItem(filemenu,1);
  710.         DisableItem(filemenu,2);
  711.         EnableItem(filemenu,3);
  712.         DisableItem(editmenu,0);
  713.         DrawMenuBar;
  714.     END;
  715.  
  716. {------------------------------------------------------------------------------}
  717. {$ EVENT }
  718. {------------------------------------------------------------------------------}
  719.  
  720.     FUNCTION ThereIsAnEvent( eventmask : Integer; VAR theevent : EventRecord ) : Boolean;
  721.     BEGIN
  722.         IF RunningUnderMultiFinder THEN
  723.             ThereIsAnEvent := WaitNextEvent( eventmask, theevent, 5, nil )
  724.         ELSE
  725.             ThereIsAnEvent := GetNextEvent( eventmask, theevent );
  726.     END;
  727.     
  728. {------------------------------------------------------------------------------}
  729.  
  730.     PROCEDURE DoAbout;
  731.     VAR
  732.         thedialog : DialogPtr;
  733.         itemhit      : Integer;
  734.     BEGIN
  735.         thedialog := GetNewDialog( 3000, nil, POINTER(-1) );
  736.         IF thedialog <> nil THEN BEGIN
  737.             ModalDialog( nil, itemhit );
  738.             CloseDialog( thedialog );
  739.             END;
  740.     END;
  741.     
  742. {------------------------------------------------------------------------------}
  743.  
  744.     PROCEDURE DoDeskAccessory( theitem : Integer );
  745.     VAR
  746.         name    : Str255;
  747.         temp    : Integer;
  748.     BEGIN
  749.         GetItem(applemenu,theitem,name);
  750.         temp := OpenDeskAcc(name);
  751.         SetPort(viewwindow);
  752.         EnableItem(editmenu,0);
  753.         DrawMenuBar;
  754.     END;
  755.     
  756. {------------------------------------------------------------------------------}
  757.  
  758.     PROCEDURE HandleAppleMenu( theitem : Integer );
  759.     BEGIN
  760.         IF theitem = 1 THEN DoAbout
  761.         ELSE DoDeskAccessory( theitem );
  762.     END;
  763.     
  764. {------------------------------------------------------------------------------}
  765.  
  766.     PROCEDURE DoClose;
  767.     BEGIN
  768.         HideWindow(viewwindow);
  769.         EnableItem(filemenu,1);
  770.         EnableItem(filemenu,2);
  771.         DisableItem(filemenu,3);
  772.         IF FrontWindow = nil THEN DisableItem(editmenu,0)
  773.         ELSE EnableItem(editmenu,0);
  774.         DrawMenuBar;
  775.     END;
  776.     
  777. {------------------------------------------------------------------------------}
  778.  
  779.     PROCEDURE DoQuit;
  780.     BEGIN
  781.         userwantstoquit := true;
  782.     END;
  783.     
  784. {------------------------------------------------------------------------------}
  785.  
  786.     PROCEDURE HandleFileMenu( theitem : Integer );
  787.     BEGIN
  788.         CASE theitem OF
  789.             1     :    DoOpenPixelPaint(1);
  790.             2    :    DoOpenPixelPaint(2);
  791.             3    :    DoClose;
  792.             5    :    DoQuit;
  793.             END;
  794.     END;
  795.     
  796. {------------------------------------------------------------------------------}
  797.  
  798.     PROCEDURE HandleEditMenu( theitem : Integer );
  799.     VAR
  800.         dummy : Boolean;
  801.     BEGIN
  802.         IF viewwindow = FrontWindow THEN Exit(HandleEditMenu);
  803.         dummy := SystemEdit( theitem-1 );
  804.     END;
  805.     
  806. {------------------------------------------------------------------------------}
  807.  
  808.     PROCEDURE HandleTheMenu( menuresult : LongInt );
  809.     VAR
  810.         themenu,theitem    : Integer;
  811.     BEGIN
  812.         themenu := HiWord( menuresult );
  813.         theitem := LoWord( menuresult );
  814.         CASE themenu OF
  815.             1    :    HandleAppleMenu(theitem);
  816.             2    :    HandleFileMenu(theitem);
  817.             3    :    HandleEditMenu(theitem);
  818.             END;
  819.         HiliteMenu(0);
  820.     END;
  821.     
  822. {------------------------------------------------------------------------------}
  823.  
  824.     FUNCTION IsItFront( somewindow : WindowPtr ) : Boolean;
  825.     BEGIN
  826.         IF somewindow <> FrontWindow THEN BEGIN
  827.             SelectWindow(somewindow);
  828.             IF somewindow <> viewwindow THEN EnableItem(editmenu,0)
  829.             ELSE DisableItem(editmenu,0);
  830.             DrawMenuBar;
  831.             IsItFront := false;
  832.             END
  833.         ELSE IsItFront := true;
  834.     END;
  835.     
  836. {------------------------------------------------------------------------------}
  837.  
  838.     FUNCTION IsItOurs( somewindow : WindowPtr ) : Boolean;
  839.     BEGIN
  840.         IsItOurs := somewindow = viewwindow;
  841.     END;
  842.     
  843. {------------------------------------------------------------------------------}
  844.  
  845.     FUNCTION ClickedInScrollBar( somept : Point ) : Boolean;
  846.     BEGIN
  847.         SetPort(viewwindow);
  848.         GlobalToLocal(somept);
  849.         IF (somept.v > viewwindow^.portrect.bottom-16) OR
  850.             (somept.h > viewwindow^.portrect.right-16) THEN ClickedInScrollBar := true
  851.         ELSE ClickedInScrollBar := false;
  852.     END;
  853.     
  854. {------------------------------------------------------------------------------}
  855.  
  856.     PROCEDURE ScrollIt( theControl : ControlHandle; thePart : Integer );
  857.     VAR
  858.         delta,oldvalue : Integer;
  859.     BEGIN
  860.         IF thePart = 0 THEN Exit(ScrollIt);
  861.         CASE thePart OF
  862.             inUpButton         : delta := -1;
  863.             inDownButton    : delta := 1;
  864.             inPageUp        : delta := -24;
  865.             inPageDown        : delta := 24;
  866.             END;
  867.         SetCtlValue(theControl, delta + GetCtlValue(theControl));
  868.         ReconstructImage;
  869.     END;
  870.     
  871. {------------------------------------------------------------------------------}
  872.  
  873.     PROCEDURE HandleScrolling( theevent : EventRecord );
  874.     VAR
  875.         whichcontrol : ControlHandle;
  876.         thepart         : Integer;
  877.     BEGIN
  878.         SetPort(viewwindow);
  879.         GlobalToLocal(theevent.where);
  880.         thepart := FindControl( theevent.where, viewwindow, whichcontrol );
  881.         IF thepart = 0 THEN Exit(HandleScrolling);
  882.         IF whichcontrol = nil THEN Exit(HandleScrolling);
  883.         IF thepart = inThumb THEN
  884.             thepart := TrackControl(whichcontrol,theevent.where,nil)
  885.         ELSE
  886.             thepart := TrackControl(whichcontrol,theevent.where,@ScrollIt);
  887.         ReconstructImage;
  888.     END;
  889.  
  890. {------------------------------------------------------------------------------}
  891.  
  892.     PROCEDURE HandleContentClick( theevent : EventRecord; somewindow : WindowPtr );
  893.     BEGIN
  894.         IF NOT IsItFront(somewindow) THEN Exit(HandleContentClick);
  895.         IF NOT IsItOurs(somewindow)  THEN Exit(HandleContentClick);
  896.         IF ClickedInScrollBar( theevent.where ) THEN HandleScrolling( theevent );
  897.     END;
  898.     
  899. {------------------------------------------------------------------------------}
  900.  
  901.     PROCEDURE HandleGrow( theevent : EventRecord; somewindow : WindowPtr );
  902.     VAR
  903.         limits                : Rect;
  904.         result                 : LongInt;
  905.         vertrect,horzrect     : Rect;
  906.     BEGIN
  907.         IF NOT IsItFront(somewindow) THEN Exit(HandleGrow);
  908.         IF NOT IsItOurs(somewindow)  THEN Exit(HandleGrow);
  909.         SetRect(limits,100,100,draggingarea.right-draggingarea.left,draggingarea.bottom-draggingarea.top);
  910.         result := GrowWindow( somewindow, theevent.where, limits );
  911.         SetPort(somewindow);
  912.         EraseRect(somewindow^.portrect);
  913.         SizeWindow(somewindow,LoWord(result),HiWord(result),true);
  914.         vertrect := VerticalFit(somewindow);
  915.         horzrect := HorizontalFit(somewindow);
  916.         MoveControl(verticalscroll,vertrect.left,vertrect.top);
  917.         SizeControl(verticalscroll,vertrect.right-vertrect.left,vertrect.bottom-vertrect.top);
  918.         MoveControl(horizontalscroll,horzrect.left,horzrect.top);
  919.         SizeControl(horizontalscroll,horzrect.right-horzrect.left,horzrect.bottom-horzrect.top);
  920.     END;
  921.     
  922. {------------------------------------------------------------------------------}
  923.  
  924.     PROCEDURE HandleGoAway( theevent : EventRecord; somewindow : WindowPtr );
  925.     BEGIN
  926.         IF NOT IsItFront(somewindow) THEN Exit(HandleGoAway);
  927.         IF NOT IsItOurs(somewindow)  THEN Exit(HandleGoAway);
  928.         IF TrackGoAway(somewindow,theevent.where) THEN BEGIN
  929.             DoClose;
  930.             END;
  931.     END;
  932.     
  933. {------------------------------------------------------------------------------}
  934.  
  935.     PROCEDURE HandleDrag( theevent : EventRecord; somewindow : WindowPtr );
  936.     BEGIN
  937.         IF NOT IsItFront(somewindow) THEN Exit(HandleDrag);
  938.         IF NOT IsItOurs(somewindow)  THEN Exit(HandleDrag);
  939.         DragWindow(somewindow,theevent.where,draggingarea);
  940.         SetPort(somewindow);
  941.         DrawControls(somewindow);
  942.         DrawGrowIcon(somewindow);
  943.     END;
  944.     
  945. {------------------------------------------------------------------------------}
  946.  
  947.     PROCEDURE HandleZoom( partcode : integer; theevent : EventRecord; somewindow : WindowPtr );
  948.     VAR
  949.         vertrect,horzrect : Rect;
  950.     BEGIN
  951.         IF NOT IsItFront(somewindow) THEN Exit(HandleZoom);
  952.         IF NOT IsItOurs(somewindow)  THEN Exit(HandleZoom);
  953.         IF TrackBox(somewindow, theevent.where, partcode) THEN BEGIN
  954.             SetPort(somewindow);
  955.             EraseRect(somewindow^.portrect);
  956.             ZoomWindow(somewindow,partcode,true);
  957.             vertrect := VerticalFit(somewindow);
  958.             horzrect := HorizontalFit(somewindow);
  959.             MoveControl(verticalscroll,vertrect.left,vertrect.top);
  960.             SizeControl(verticalscroll,vertrect.right-vertrect.left,vertrect.bottom-vertrect.top);
  961.             MoveControl(horizontalscroll,horzrect.left,horzrect.top);
  962.             SizeControl(horizontalscroll,horzrect.right-horzrect.left,horzrect.bottom-horzrect.top);
  963.             END;
  964.     END;
  965.     
  966. {------------------------------------------------------------------------------}
  967.  
  968.     PROCEDURE HandleTheSystem( theevent : EventRecord; somewindow : WindowPtr );
  969.     BEGIN
  970.         SystemClick(theevent,somewindow);
  971.         IF FrontWindow = nil THEN DisableItem(editmenu,0)
  972.         ELSE IF FrontWindow = viewwindow THEN DisableItem(editmenu,0)
  973.         ELSE EnableItem(editmenu,0);
  974.         DrawMenuBar;
  975.     END;
  976.     
  977. {------------------------------------------------------------------------------}
  978.  
  979.     PROCEDURE HandleTheMouse( theevent : EventRecord );
  980.     VAR
  981.         somewindow : WindowPtr;
  982.     BEGIN
  983.         CASE FindWindow( theevent.where, somewindow ) OF
  984.             inSysWindow    :    HandleTheSystem(theevent,somewindow);
  985.             inMenuBar    :    HandleTheMenu( MenuSelect(theevent.where) );
  986.             inDrag        :    HandleDrag(theevent,somewindow);            
  987.             inContent    :    HandleContentClick(theevent,somewindow);
  988.             inGrow        :    HandleGrow(theevent,somewindow);
  989.             inGoAway    :    HandleGoAway(theevent,somewindow);
  990.             inZoomIn    :    HandleZoom(inZoomIn,theevent,somewindow);
  991.             inZoomOut     :    HandleZoom(inZoomOut,theevent,somewindow);
  992.         END;
  993.     END;
  994.     
  995. {------------------------------------------------------------------------------}
  996.  
  997.     PROCEDURE HandleTheKeyboard( theevent : EventRecord );
  998.     BEGIN
  999.         IF BAND(theevent.modifiers,cmdkey) = cmdkey THEN
  1000.             HandleTheMenu( MenuKey( CHR(BAND(theevent.message,charcodemask)) ) );
  1001.     END;
  1002.         
  1003. {------------------------------------------------------------------------------}
  1004.  
  1005.     PROCEDURE HandleTheActivate( theevent : EventRecord );
  1006.     BEGIN
  1007.         IF NOT IsItOurs(WindowPtr(theevent.message)) THEN Exit(HandleTheActivate);
  1008.         IF BAND(theevent.modifiers,activeFlag) <> 0 THEN BEGIN
  1009.             HiliteControl( horizontalscroll, 0 );
  1010.             HiliteControl( verticalscroll, 0 );
  1011.             DisableItem(editmenu,0);
  1012.             END
  1013.         ELSE BEGIN
  1014.             HiliteControl( horizontalscroll, 255 );
  1015.             HiliteControl( verticalscroll, 255 );
  1016.             EnableItem(editmenu,0);
  1017.             END;
  1018.         DrawControls(viewwindow);
  1019.         DrawGrowIcon(viewwindow);
  1020.         DrawMenuBar;
  1021.     END;
  1022.     
  1023. {------------------------------------------------------------------------------}
  1024.  
  1025.     PROCEDURE HandleTheUpdate( theevent : EventRecord );
  1026.     BEGIN
  1027.         IF NOT IsItOurs(WindowPtr(theevent.message)) THEN Exit(HandleTheUpdate);
  1028.         SetPort(viewwindow);
  1029.         BeginUpdate(viewwindow);
  1030.         EraseRect(viewwindow^.portrect);
  1031.         EndUpdate(viewwindow);
  1032.         AdjustScrollLimits;
  1033.         DrawControls(viewwindow);
  1034.         DrawGrowIcon(viewwindow);
  1035.     END;
  1036.     
  1037. {------------------------------------------------------------------------------}
  1038.  
  1039.     PROCEDURE HandleTheEvent( theevent : EventRecord );
  1040.     BEGIN
  1041.         CASE theevent.what OF
  1042.             mouseDown             : HandleTheMouse( theevent );
  1043.             keyDown,autoKey     : HandleTheKeyboard( theevent );
  1044.             activateEvt            : HandleTheActivate( theevent );
  1045.             updateEvt            : HandleTheUpdate( theevent );
  1046.             OTHERWISE { nothing } ;
  1047.         END;
  1048.     END;
  1049.     
  1050. {------------------------------------------------------------------------------}
  1051. {$ MAIN }
  1052. {------------------------------------------------------------------------------}
  1053.  
  1054.     PROCEDURE MainEventLoop;
  1055.     BEGIN
  1056.         userwantstoquit := false;
  1057.         REPEAT
  1058.             SystemTask;
  1059.             InitCursor;
  1060.             IF ThereIsAnEvent( everyevent, viewevent ) THEN HandleTheEvent( viewevent );
  1061.         UNTIL userwantstoquit;
  1062.     END;
  1063.     
  1064. {------------------------ the main program starts here -------------------------}
  1065.  
  1066. BEGIN
  1067.  
  1068.     InitThings;    
  1069.     UnloadSeg(@InitThings);
  1070.     MainEventLoop;                
  1071.     ResumeProc;
  1072.  
  1073. END.